function TS = joinTS(ts1, ts2, dim, type)
% TS = sintersect(ts1, ts2, type)
% Intersect two sesame structures (can be 2D or 3D)
%    ts1, ts2 - Sesame structures
%    dim        - 'row', 'col', 'both', 'daterange', 'headers', 'rownames'
%               - join dimension (default 'both')
%    type       - 'intersect', 'union'
%               - Intersection type (default 'intersect')
%
% Usage:
%    Intersect two TS structures over headers and dates.  Column order
%    matches ts2 then ts1.
%
% Example: 
%    TS = joinTS(ts1, {'header1','header2'}, 'headers');
%    TS = joinTS(ts1, ts2, 'daterange', 'union');
%
% functionality is not set up for union of 3D covm 
%

if nargin < 4; type = 'intersect'; end
if nargin < 3; dim = 'both'; end
if nargin < 2; TS = ts1; return; end

if ~(strcmp(type, {'intersect' 'union'}))>0 || ...
    ~(strcmp(dim, {'row', 'col', 'both', 'daterange', 'headers','rownames'}))>0 
   error('Invalid join or dimension type.')
end

if isstruct(ts1) && isstruct(ts2)
  if (ndims(ts1.data) > 2 || ndims(ts2.data) > 2) && strcmp(type, 'union')
    error('Invalid join type for 3D TS structures.  Unions not supported.')
  end
end

TS = ts1;

if isempty(ts2)
   return
end

if strcmp(dim, 'daterange')
    if strcmp(type, 'intersect')
        I = find(ts1.dates >= ts2(1) & ts1.dates <= ts2(2));
        TS.dates = ts1.dates(I);
        if ndims(ts1.data) == 2
            TS.data = ts1.data(I, :);
        else  %3D covm
            TS.data = ts1.data(:, :, I);
        end
    else
        dtlist = TSdatelist(min(ts1.dates(1), ts2(1)), max(ts1.dates(end),ts2(end)));
        TS = joinTS(ts1,buildTS([],ts1.header,dtlist),'union');        
    end
    return
end

if strcmp(dim, 'headers')
    if ~isstruct(ts2)
      temp = ts2;
      ts2 = struct;
      ts2.header = temp;
    end
    dim = 'col';
end

if strcmp(dim, {'rownames'})
    if strcmp(type, 'intersect')
        [d I1] = intersect(ts1.rownames, ts2.rownames);
        I1 = I1(:);
        if isempty(I1)
            TS = [];
            return
        end
        dt1 = sort(I1);
        hdr1 = 1:length(ts1.header);
        
    else 
        dt2 = sort(union(ts1.rownames, ts2.rownames));
        if size(dt2,1) == 1
          dt2 = dt2';
        end
        ts2 = insertTS(ts2, buildTS([],ts2.header,dt2, dim), dim); %add rows to ts2
        ts1 = insertTS(ts1, buildTS([],ts1.header,dt2, dim), dim); %add rows to ts1
    end
end

if strmatch(dim, {'rows', 'both'})
    if strcmp(type, 'intersect')
        [d I1] = intersect(ts1.dates, ts2.dates);
        I1 = I1(:);
        if isempty(I1)
            TS = [];
            return
        end
        dt1 = sort(I1);
        hdr1 = 1:length(ts1.header);
        
    else 
        dt2 = sort(union(ts1.dates, ts2.dates));
        if size(dt2,1) == 1
          dt2 = dt2';
        end
        ts2 = insertTS(ts2, buildTS([],ts2.header,dt2)); %add rows to ts2
        ts1 = insertTS(ts1, buildTS([],ts1.header,dt2)); %add rows to ts1
    end
end

if strmatch(dim, {'col', 'both'})
    if strcmp(type, 'intersect')
        [d I1 I2] = intersect(ts1.header, ts2.header);
        [d temp] = sort(I2);
        if isempty(I1)
            TS = [];
            return
        end
        hdr1 = I1(temp);
        if isfield(ts1, 'dates')
          dt1 = 1:length(ts1.dates);
        else 
          dt1 = 1:length(ts1.rownames);
        end
    else 
        [d, I2, I1] = union(ts2.header, ts1.header);
        hdr2 = [ts1.header(sort(I1)) ts2.header(sort(I2))];
        ts2 = insertTS(ts2, buildTS([],hdr2,ts2.dates)); % add columns to ts2
        ts1 = insertTS(ts1, buildTS([],hdr2,ts1.dates));  % add columns to ts1
    end
end

if strcmp(type, 'intersect')
    if isfield(ts1, 'dates')
      TS.dates = ts1.dates(dt1);
    else 
      TS.rownames = ts1.rownames(dt1);
    end
    TS.header = ts1.header(hdr1);
    if ndims(ts1.data) == 2
        TS.data = ts1.data(dt1, hdr1);
    else  %3D covm
        TS.data = ts1.data(hdr1, hdr1, dt1);
    end
else
    if ~strcmp(dim, 'rownames')
      tsa = joinTS(ts1,ts2);
      tsb = joinTS(ts2,ts1);
    else 
      tsa = joinTS(ts1,ts2,'col');
      tsb = joinTS(ts2,ts1,'col');
    end
    if (isempty(tsa) == 0) && (isempty(tsb) == 0)
        top = tsa;
        top.data(isnan(tsa.data)) = tsb.data(isnan(tsa.data));
        if ~strcmp(dim, 'rownames')
          TS = insertTS(top, ts1);
        else
          TS = insertTS(top, ts1, dim);
        end
    end
end
return
